package com.figure.web.util;

import com.figure.web.exception.ExceptionCodeEnum;

public abstract class BaseAPIResult<T, S extends BaseAPIResult<T, S>> {
	
	public static class Status {
		public static final int CODE_OK = 0;

		private int code;
		private String msg;

		public Status() {

		}

		public Status(int code, String msg) {
			super();
			this.code = code;
			this.msg = msg;
		}

		/**
		 * @return the code
		 */
		public int getCode() {
			return code;
		}

		/**
		 * @param code
		 *            the code to set
		 */
		public void setCode(int code) {
			this.code = code;
		}

		/**
		 * @return the message
		 */
		public String getMsg() {
			return msg;
		}

		/**
		 * @param msg
		 *            the message to set
		 */
		public void setMsg(String msg) {
			this.msg = msg;
		}

	}

	protected Status status;
	protected T data;
	
	
	public static APIResult okResult(Object data) {
		return 	okResult(APIResult.class, data);
	}

	public static APIResult failResult(int code, String msg) {
		return failResult(APIResult.class, code, msg, null);
	}

	public static APIResult failResult(ExceptionCodeEnum exceptionCodeEnum, Object data) {
		return failResult(APIResult.class, exceptionCodeEnum.getCode(), exceptionCodeEnum.getMessage(), data);
	}

	public static APIResult failResult(int code, String msg, Object data) {
		return failResult(APIResult.class, code, msg, data);
	}

	public static <C extends BaseAPIResult<T, C>, T> C okResult(Class<C> subClass, T data) {
		C c = create(subClass);
		c.setStatus(new Status(Status.CODE_OK, "success"));
		c.setData(data);
		return c;
	}

	public static <C extends BaseAPIResult<T, C>, T> C failResult(Class<C> subClass, int code, String msg, T data) {
		C c = create(subClass);
		c.setStatus(new Status(code, msg));
		c.setData(data);
		return c;
	}

	public static <C extends BaseAPIResult<T, C>, T> C create(Class<C> subClass) {
		C ins;
		try {
			ins = subClass.newInstance();
		} catch (Exception e) {
			throw new RuntimeException("error when initiate subclass of AbstractAPIResult.", e);
		} 
		
		return ins;
	}

	public Status getStatus() {
		return status;
	}

	public void setStatus(Status status) {
		this.status = status;
	}

	/**
	 * @return the data
	 */
	public T getData() {
		return data;
	}

	/**
	 * @param data
	 *            the data to set
	 */
	public void setData(T data) {
		this.data = data;
	}

}

